/*
 * 数据规范：点标号（不是id）从0开始
 * 标签全为正数，不能有负数
 */

#ifndef GFD_GRAPH_H
#define GFD_GRAPH_H

#include <string>
#include <vector>
#include <map>
#include <set>
#include "PropertyValue.h"
#include <algorithm>

enum EdgeState {
    undefined,
    in,
    out,
};

//define a pair of PropertyName and PropertyValue
class Property {

public:
    int _propertyName;
    PropertyValue _propertyValue;

    friend bool operator<(Property a, Property b);

    Property(int propertyName, PropertyValue propertyValue);

};

/* Edge
 *
 */
class Edge {

private:

    int _from{0};
    int _to{0};
    int _label{0};
    EdgeState _edgeState{undefined};

public:

    [[nodiscard]] int getFromVertex() const;

    [[nodiscard]] int getToVertex() const;

    [[nodiscard]] int getLabel() const;

    [[nodiscard]] EdgeState getEdgeState() const;

    Edge() = default;

    Edge(const Edge &);

    Edge(int from, int to, int label, EdgeState edgeState);

    void changeEdgeState(EdgeState edgeState);

    void update(std::map<int, int> &vertexMap);

//    判断两条边标签是否相等
    [[nodiscard]] bool labelEqual(const Edge &) const;

//    判断该边的标签是否等于查询值
    [[nodiscard]] bool labelEqual(int queryLabel) const;

    bool operator<(const Edge &ano) const {
        if (_from == ano._from)
            return _to < ano._to;
        return _from < ano._from;
    }

};

using EdgeModel = Edge;

/*
 * Vertex
 *
 */
class Vertex {

    int _label{0};

public:

    [[nodiscard]] int getId() const;

    [[nodiscard]] int getLabel() const;

    std::set<Property> PropertySet;

    std::vector<Edge> inEdges;

    std::vector<Edge> outEdges;

    Vertex() = default;

    Vertex(int id, int label);

    Vertex(const Vertex &vertex);

    void updateEdges(std::map<int, int> &vertexMap);

    friend bool operator<(const Vertex &a, const Vertex &b);

//    根据标签查询指向该点的边
    std::vector<Edge> findInEdge(int queryLabel);

//    根据标签查询该点指向的边
    std::vector<Edge> findOutEdge(int queryLabel);

//    入度
    [[nodiscard]] int getInDegree() const;

//    出度
    [[nodiscard]] int getOutDegree() const;

//  判断两点标签是否相等
    [[nodiscard]] bool labelEqual(const Vertex &) const;

//    判断该点的标签是否等于查询值
    [[nodiscard]] bool labelEqual(int queryLabel) const;

    int _id{-1};
};


/*
 * Graph
 */
class Graph : public std::vector<Vertex> {
    int _id{-1};

public:

    Graph() = default;

    explicit Graph(int id);

    explicit Graph(std::string fileName);

    Graph(const Graph &graph);

    int countEdge();

    static void makeEdge(Vertex &from, Vertex &to, int label);

    void updateVertexLabelInfo(std::set<int> &vertexLabelSet) const;

    void updateEdgeLabelInfo(std::set<EdgeModel> &edgeLabelSet) const;

    void updatePropertySetInfo(std::map<std::pair<int, int>, std::set<PropertyValue>> &propertySet) const;

    friend std::ostream &operator<<(std::ostream &out, Graph &graph) {
        for (auto &ver: graph) {
            out << ver.getId() << "(" << ver.getLabel() << ") ";
        }
        return out;
    }

    void fileOut(std::ofstream &fOut);
};


#endif //GFD_GRAPH_H
